#include <algorithm>

#include "gamekit/Scene.h"
#include "gamekit/Component.h"
#include "gamekit/Window.h"
#include "gamekit/Game.h"

using namespace gamekit;

bool SortPredicate(const SharedPointer<Canvas>& d1, const SharedPointer<Canvas>& d2)
{
	return d1->zIndex() < d2->zIndex();
}

Scene::Scene(SafePointer<Game> game):
	m_game(game),
	m_canvasesCache(NULL),
	m_lockCanvasesCache(false)
{

}

Scene::~Scene()
{
	m_canvasesCache.clear();

	for(std::vector<Component*>::const_iterator it = m_components.begin(); it != m_components.end(); it++)
	{
		delete (*it);
	}

	m_components.clear();
}

void Scene::init(void)
{
	beginUpdateCanvasesCache();

	for(std::vector<Component*>::const_iterator it = m_components.begin(); it != m_components.end(); it++)
	{
		Component* component = *it;
		component->init();
	}

	endUpdateCanvasesCache();
}

void Scene::update(const uint& elapsed)
{
	for(std::vector<Component*>::const_iterator it = m_components.begin(); it != m_components.end(); it++)
	{
		Component* component = *it;
		component->update(elapsed);
	}
}

void Scene::draw(const uint& elapsed)
{
	std::vector<SharedPointer<Canvas> >::const_iterator it;

	for(it = m_canvasesCache.begin(); it != m_canvasesCache.end(); it++)
	{
		SharedPointer<Canvas> drawing = *it;
		drawing->draw(elapsed);
	}
}

SafePointer<Game> Scene::game(void) const
{
	return m_game;
}

SafePointer<Window> Scene::window(void) const
{
	return m_game->window();
}

void Scene::updateCanvasesCache(void)
{
	if(m_lockCanvasesCache)
	{
		return;
	}

	m_canvasesCache.clear();

	std::vector<Component*>::const_iterator cit;

	for(cit = m_components.begin(); cit != m_components.end(); cit++ )
	{
		Component* component = *cit;
		std::vector<SharedPointer<Canvas> > canvases = component->canvases();
		std::vector<SharedPointer<Canvas> >::const_iterator dit;

		for(dit = canvases.begin(); dit != canvases.end(); dit++)
		{
			m_canvasesCache.push_back(*dit);
		}
	}

	std::sort(m_canvasesCache.begin(), m_canvasesCache.end(), SortPredicate);
}

void Scene::beginUpdateCanvasesCache(void)
{
	m_lockCanvasesCache = true;
}

void Scene::endUpdateCanvasesCache(void)
{
	m_lockCanvasesCache = false;

	updateCanvasesCache();
}
